package com.asman.vr

import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Build
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.webkit.*
import android.webkit.WebSettings.LOAD_NO_CACHE
import android.widget.ProgressBar
import androidx.annotation.RequiresApi
import com.github.lzyzsd.jsbridge.BridgeUtil
import com.github.lzyzsd.jsbridge.BridgeWebView
import com.github.lzyzsd.jsbridge.BridgeWebViewClient
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import java.io.UnsupportedEncodingException
import java.net.URLDecoder
import kotlin.math.abs

/**
 * author : ybk
 * date   : 2019-07-25 11:06
 * desc   : 封装了和 JS 交互
 */
open class BaseWebView : BridgeWebView {

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        init()
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(
        context, attrs, defStyle
    ) {
        init()
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    constructor(context: Context) : super(context) {
        init()
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    @SuppressLint("SetJavaScriptEnabled", "ClickableViewAccessibility")
    open fun init() {
        val webSettings = this.settings
        webSettings.domStorageEnabled = true
        webSettings.blockNetworkImage = false
        webSettings.javaScriptCanOpenWindowsAutomatically = true
        webSettings.loadsImagesAutomatically = true
        webSettings.savePassword = false
        webSettings.javaScriptEnabled = true //是否允许执行JavaScript脚本
        webSettings.setSupportZoom(false) //缩放
//        webSettings.setSupportZoom(true);  //支持缩放，默认为true。是下面那个的前提。

        webSettings.builtInZoomControls =
            true //设置WebView是否使用其内置的变焦机制，该机制集合屏幕缩放控件使用，默认是false，不使用内置变焦机制。
        webSettings.useWideViewPort =
            true //设置WebView是否使用viewport，当该属性被设置为false时，加载页面的宽度总是适应WebView控件宽度；当被设置为true，当前页面包含viewport属性标签，在标签中指定宽度值生效，如果页面不包含viewport标签，无法提供一个宽度值，这个时候该方法将被使用。
        webSettings.databaseEnabled = true //设置是否开启数据库存储API权限，默认false，未开启，可以参考
        webSettings.setAppCacheEnabled(true) //设置Application缓存API是否开启，默认false，
        webSettings.pluginState = WebSettings.PluginState.ON
        webSettings.allowFileAccess = true //设置在WebView内部是否允许访问文件，默认允许访问。
        webSettings.loadWithOverviewMode = true //设置WebView是否使用预览模式加载界面。
        webSettings.cacheMode =
            LOAD_NO_CACHE //重写缓存被使用到的方法，该方法基于Navigation Type，加载普通的页面，将会检查缓存同时重新验证是否需要加载，如果不需要重新加载，将直接从缓存读取数据，允许客户端通过指定LOAD_DEFAULT、LOAD_CACHE_ELSE_NETWORK、LOAD_NO_CACHE、LOAD_CACHE_ONLY其中之一重写该行为方法，默认值LOAD_DEFAULT
//        webSettings.mixedContentMode = WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE
        webSettings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW//TODO http https 混合使用

        this.setOnTouchListener(object : OnTouchListener {
            private var startx: Float = 0.toFloat()
            private var starty: Float = 0.toFloat()
            private var offsetx: Float = 0.toFloat()
            private var offsety: Float = 0.toFloat()

            override fun onTouch(v: View, event: MotionEvent): Boolean {
                when (event.action) {
                    MotionEvent.ACTION_DOWN -> {
                        v.parent.requestDisallowInterceptTouchEvent(true)
                        startx = event.x
                        starty = event.y
                    }
                    MotionEvent.ACTION_MOVE -> {
                        offsetx = abs(event.x - startx)
                        offsety = abs(event.y - starty)
                        if (offsetx > offsety) {
                            v.parent.requestDisallowInterceptTouchEvent(true)
                        } else {
                            v.parent.requestDisallowInterceptTouchEvent(false)
                        }
                    }
                    else -> {
                    }
                }
                return false
            }
        })
        registerHandler()
    }

    fun setAppVersionName(versionName: String) {
        //JS交互 前端需要此参数
        this.settings.userAgentString =
            this.settings.userAgentString + "${resources.getString(R.string.config_webview_agent)} xiaoniuge/$versionName"
    }

    /**
     * 打开url，加载进度，标题更新
     * @param url 连接
     * @param progressBar 加载进度条
     * @param listener 标题回调
     */
    fun loadUrl(
        url: String?, progressBar: ProgressBar?,
        listener: ((titles: MutableList<String>, title: String, progress: Int) -> Unit)?
    ) {
        val titles = ArrayList<String>()
        this.webChromeClient = object : WebChromeClient() {
            override fun onReceivedTitle(view: WebView, title: String) {
                super.onReceivedTitle(view, title)
                if (listener != null) {
                    titles.add(title)
                    if (title.isNotEmpty()) {
                        listener.invoke(titles, title, progress)
                    }
                }
            }

            override fun onGeolocationPermissionsShowPrompt(
                origin: String, callback: GeolocationPermissions.Callback
            ) {
                callback.invoke(origin, true, false)
                super.onGeolocationPermissionsShowPrompt(origin, callback)
            }

            override fun onProgressChanged(view: WebView, newProgress: Int) {
                if (progressBar != null) {
                    listener?.invoke(titles, title, progress)
                    if (newProgress < 100) {
                        progressBar.visibility = View.VISIBLE
                        progressBar.progress = newProgress
                    } else {
                        progressBar.visibility = View.GONE
                    }
                }
            }
        }

        this.webViewClient = object : BridgeWebViewClient(this) {
            @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
            override fun shouldOverrideUrlLoading(
                view: WebView?,
                request: WebResourceRequest?
            ): Boolean {
                val requestUrl: String
                try {
                    requestUrl = URLDecoder.decode(request?.url.toString(), "UTF-8")
                } catch (e: UnsupportedEncodingException) {
//                    e.printStackTrace()
                    return true
                }

                //这里需要单独判断，否则jsBridge注册失败
                if (requestUrl.startsWith(BridgeUtil.WVJB_BRIDGE_LOADED)
                    || requestUrl.startsWith(BridgeUtil.WVJB_RETURN_DATA)
                    || requestUrl.startsWith(BridgeUtil.WVJB_QUEUE_HAS_MESSAGE)
                ) {
                    //重载父类BridgeWebViewClient的方案
                    return super.shouldOverrideUrlLoading(view, requestUrl)
                } else if (requestUrl.startsWith("http:") || requestUrl.startsWith("https:")) {
                    return if (callBack1 == null) {
                        //这里直接重载 WebViewClient 的方法即可，
                        super.shouldOverrideUrlLoading(view, request)
                    } else {
                        callBack1!!.invoke(view, request?.url.toString())
                        true
                    }
                } else {
                    try {
                        val intent = Intent(Intent.ACTION_VIEW, request?.url)
                        context.startActivity(intent)
                        return true
                    } catch (e: Exception) {
                    }
                    return true
                }
            }
        }

        if (url != null) {
            this.loadUrl(url)
        }
    }

    var callBack1: ((view: WebView?, url: String?) -> Boolean)? = null

    fun setOnShouldOverrideUrlLoading(callBack1: (view: WebView?, url: String?) -> Boolean) {
        this.callBack1 = callBack1
    }

    /**
     * Native 初始化完成
     */
    @Deprecated(message = "暂时不用")
    fun initFinish() {
        this.callHandler(INIT_FINISH, null) { }
    }

    /**
     * 刷新H5
     */
    fun refreshH5() {
        this.callHandler(REFRESH_H5, null) {}
    }

    /**
     * 获取分享信息
     */
    fun getH5ShareParams(callBack: ((data: ShareInfoRes?) -> Unit)) {
        this.callHandler(H5_SHARE_PARAMS, null) { response ->
            val data: BaseJSBridgeDataT<ShareInfoRes> = Gson().fromJson(
                response, object : TypeToken<BaseJSBridgeDataT<ShareInfoRes>>() {}.type
            )
            callBack.invoke(data.result)
        }
    }

    /**
     * 实时语音 事件回调 通知H5
     */
    fun <T> notifyTrtcH5(data: NotifyTrtcH5<T>) {
//        log("joinRoom====notifyTrtcH5==${data}")
        this.callHandler(NOTIFY_RTRC_H5, Gson().toJson(data)) { response ->
//            showToastDebug(Gson().toJson(response))
        }
    }

    /**
     * 注册方法
     */
    @SuppressLint("LongLogTag")
    private fun registerHandler() {
        //跳转到原生页面
        // params:{ appUrl: "asman://xxx/xxx?url=http://xxx/xxx" } response:{ code: 10000,error: "",result: null }
        this.registerHandler(JUMP_TO_NATIVE_VIEW) { params, function ->
            val paramsData = Gson().fromJson(params, JumpToNativeViewParam::class.java)
            if (paramsData?.appUrl != null) {
                callBack?.jump2NativePage(paramsData.appUrl)
                function.onCallBack(Gson().toJson(BaseJSBridgeData()))
            } else {
                function.onCallBack(Gson().toJson(BaseJSBridgeData("-10000", "参数错误")))
            }
        }

        //唤起原生分享，无需参数
        this.registerHandler(SHOW_SHARE_VIEW) { _, function ->
            callBack?.showShareView()
            function.onCallBack(Gson().toJson(BaseJSBridgeData()))
        }

        //分享到微信小程序--2020-2-24
        this.registerHandler(SHARE_WX_MINI_PROGRAM) { shareInfo, function ->
            val shareMiniProgramInfo = Gson().fromJson(shareInfo, ShareMiniProgramInfo::class.java)
            callBack?.shareWXMiniProgram(shareMiniProgramInfo)
            function.onCallBack(Gson().toJson(BaseJSBridgeData()))
        }

        //获取用户信息，无需参数
        this.registerHandler(GET_USER_INFO) { _, function ->
            callBack?.getUserInfo {
                function.onCallBack(Gson().toJson(BaseJSBridgeDataT(result = it)))
            }
        }

        //顶部导航显示隐藏
        // params:{ isHidden: 1隐藏，0显示 }
        this.registerHandler(TOP_NAVIGATION_BAR) { params, function ->
            val paramsData = Gson().fromJson(params, TopNavigationBarParam::class.java)
            if (paramsData?.isHidden != null) {
                callBack?.topNavigationBar(paramsData.isHidden)
                function.onCallBack(Gson().toJson(BaseJSBridgeData()))
            } else {
                function.onCallBack(Gson().toJson(BaseJSBridgeData("-10000", "参数错误")))
            }
        }

        //后退
        this.registerHandler(GO_BACK) { _, function ->
            callBack?.goBack()
            function.onCallBack(Gson().toJson(BaseJSBridgeData()))
        }

        //关闭当前webview
        this.registerHandler(CLOSE_NATIVE_VIEW) { _, function ->
            callBack?.closeNativeView()
            function.onCallBack(Gson().toJson(BaseJSBridgeData()))
        }

        //开始录音
        this.registerHandler(RECORD_BEGIN) { _, function ->
            callBack?.recordBegin {
                function.onCallBack(Gson().toJson(BaseJSBridgeData("10000")))
            }
        }

        //获取录音
        this.registerHandler(GET_RECORD) { _, function ->
            callBack?.getRecord { base64, isSuccess ->
                if (isSuccess == true) {
                    //返回it base64
                    function.onCallBack(
                        Gson().toJson(
                            BaseJSBridgeDataT(
                                code = "10000",
                                result = base64
                            )
                        )
                    )
                } else {
                    function.onCallBack(
                        Gson().toJson(
                            BaseJSBridgeDataT(
                                code = "-10000",
                                msg = "录音失败",
                                result = ""
                            )
                        )
                    )
                }
            }
        }

        //停止录音
        this.registerHandler(STOP_RECORD) { _, function ->
            callBack?.stopRecord()
            function.onCallBack(Gson().toJson(BaseJSBridgeData()))
        }

        this.registerHandler(SAVE_LOCAL_PARAM_DATA) { params, function ->
            //params={"key":"kkkkk","value":"vvvvv"}
            val data = Gson().fromJson(params, SaveLocalDataParam::class.java)
            callBack?.saveLocalParamData(data.key, data.value)
            function.onCallBack(Gson().toJson(BaseJSBridgeData()))
        }

        this.registerHandler(GET_LOCAL_PARAM_DATA) { params, function ->
            //params={"key":"kkkkk""}
            val data = Gson().fromJson(params, SaveLocalDataParam::class.java)
            callBack?.getLocalParamData(data.key)
            function.onCallBack(Gson().toJson(BaseJSBridgeData()))
        }

        this.registerHandler(GET_STATUS_BAR_HEIGHT) { _, function ->
            function.onCallBack(Gson().toJson(BaseJSBridgeDataT(result = callBack?.getStatusBarHeight())))
        }

        this.registerHandler(CALL_APP_ARTC) { params, function ->
            val data = Gson().fromJson(params, CallAppTrtc::class.java)
            callBack?.callAppTrtc(data) {
                function.onCallBack(Gson().toJson(it))
            }
        }

        this.registerHandler(GET_VERSION) { _, function ->
            function.onCallBack(Gson().toJson(BaseJSBridgeDataT(result = callBack?.getVersion())))
        }

        ///////////////////////////////////////////////////////////////////////
        //以下跳转都可以使用 jumpToNativeView  ---后面需要改正过来
        ///////////////////////////////////////////////////////////////////////

        //跳转到设计师页面  入参designer={"designerId":1111}
        this.registerHandler(SWITCH_TO_DESIGNER_SHOP_VIEW) { designer, function ->
            try {
                val designerDetailParam =
                    Gson().fromJson(designer, DesignerDetailParam::class.java)
                callBack?.switchToDesignerShopView(designerDetailParam)
                function.onCallBack(Gson().toJson(BaseJSBridgeData()))
            } catch (e: NumberFormatException) {
                function.onCallBack(
                    Gson().toJson(
                        BaseJSBridgeData(
                            code = "-10000",
                            msg = e.toString()
                        )
                    )
                )
                Log.e(SWITCH_TO_DESIGNER_SHOP_VIEW, e.toString())
            }
        }

        //跳转到报价单  decorationInfo= {"decorationInfo":{"schemeid":11,.....}}
        this.registerHandler(SWITCH_TO_QUOTATION_VIEW) { decorationInfo, function ->
            //FIXME  这里json参数可以简化
            try {
                val paramData = Gson().fromJson(decorationInfo, DecorateDetailParamOut::class.java)
                if (paramData.decorationInfo == null) {
                    val data = Gson().toJson(
                        BaseJSBridgeData(
                            code = "-10000",
                            msg = "格式不对 需要这样的：{\"decorationInfo\":{\"schemeid\":11,.....}}"
                        )
                    )
                    function.onCallBack(data)
                } else {
                    callBack?.switchToQuotationView(paramData.decorationInfo)
                    function.onCallBack(Gson().toJson(BaseJSBridgeData()))
                }
            } catch (e: Exception) {
                function.onCallBack(
                    Gson().toJson(BaseJSBridgeData(code = "-10000", msg = e.toString()))
                )
                Log.e(SWITCH_TO_QUOTATION_VIEW, e.toString())
            }
        }

        //跳转到登录页
        this.registerHandler(SHOW_LOGIN_VIEW) { _, function ->
            //            val userInfo = callBack?.showLoginView()//登陆成功之后返回用户信息 //FIXME app不会存在未登录的访问的情况
//            function.onCallBack(Gson().toJson(BaseJSBridgeDataT("10000", "", userInfo)))
        }

        //跳转到分享中转页
        this.registerHandler(SHOW_SHARE_PAGE_VIEW) { info, function ->
            try {
                val sharePageViewParam = Gson().fromJson(info, SharePageViewParam::class.java)
                callBack?.showSharePageView(sharePageViewParam)
                function.onCallBack(Gson().toJson(BaseJSBridgeData()))
            } catch (e: Exception) {
                function.onCallBack(
                    Gson().toJson(BaseJSBridgeData(code = "-10000", msg = e.toString()))
                )
                Log.e(SHOW_SHARE_PAGE_VIEW, e.toString())
            }
        }


        //跳转到分享中转页
        this.registerHandler(SHOW_GOODS_DETAIL) { info, function ->
            try {
                val goodsDetailParam = Gson().fromJson(info, GoodsDetailParam::class.java)
                callBack?.showGoodsDetailView(goodsDetailParam)
                function.onCallBack(Gson().toJson(BaseJSBridgeData()))
            } catch (e: Exception) {
                function.onCallBack(
                    Gson().toJson(BaseJSBridgeData(code = "-10000", msg = e.toString()))
                )
                Log.e(SHOW_GOODS_DETAIL, e.toString())
            }
        }
    }

    private var callBack: OnJSBridgeCallBack? = null

    fun setOnJSBridgeCallBackListener(callBack: OnJSBridgeCallBack) {
        this.callBack = callBack
    }

    override fun destroy() {
        val parent = this.parent as ViewGroup
        this.stopLoading()
        this.removeAllViews()
        super.destroy()
        parent.removeView(this)
    }

    companion object {
        private const val INIT_FINISH = "initFinish"//初始化完成
        private const val REFRESH_H5 = "refreshH5"//刷新页面
        private const val H5_SHARE_PARAMS = "h5ShareParams"//APP获取H5分享参数
        private const val NOTIFY_RTRC_H5 = "notifyTrtcH5"//实时语音事件变化，通知H5

        private const val JUMP_TO_NATIVE_VIEW = "jumpToNativeView"//跳转到原生页面

        private const val SHOW_SHARE_VIEW = "showShareView"//唤起原生分享，无需参数
        private const val SHARE_WX_MINI_PROGRAM = "shareWXMiniProgram"//分享到微信小程序--2020-2-24

        private const val GET_USER_INFO = "getUserInfo"//获取用户信息，无需参数
        private const val TOP_NAVIGATION_BAR = "topNavigationBar"//顶部导航显示隐藏
        private const val GO_BACK = "goBack"//后退
        private const val CLOSE_NATIVE_VIEW = "closeNativeView"//关闭当前webview

        private const val SAVE_LOCAL_PARAM_DATA = "saveLocalParamData"//保存变量到本地存储
        private const val GET_LOCAL_PARAM_DATA = "getLocalParamData"//从本地存储获取变量

        private const val RECORD_BEGIN = "recordBegin"//开始录音
        private const val GET_RECORD = "getRecord"//获取录音
        private const val STOP_RECORD = "recordStop"//停止录音-不需要返回base64录音文件

        private const val GET_STATUS_BAR_HEIGHT = "getStatusBarHeight"//获取状态栏高度

        private const val CALL_APP_ARTC = "callAppTrtc"//实时音视频相关功能

        private const val GET_VERSION = "getVersion"//获取app版本号  1.2.1

        ///////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////
        //以下跳转都可以使用 jumpToNativeView  ---后面需要改正过来
        private const val SWITCH_TO_DESIGNER_SHOP_VIEW =
            "switchToDesignerShopView"//跳转到设计师页面  designerId
        private const val SWITCH_TO_QUOTATION_VIEW =
            "switchToQuotationView"//跳转到报价单  decorationInfo  json
        private const val SHOW_LOGIN_VIEW = "showLoginView" //跳转到登录页
        private const val SHOW_SHARE_PAGE_VIEW = "showSharePageView"//跳转到分享中转页
        private const val SHOW_GOODS_DETAIL = "nativationToGoodsDetail"//跳转商品详情页

    }
}

